#include "tetris.h"
#include "ui_tetris.h"
#include <qrect.h>
#include <time.h>
#include <QMessageBox>
#include <QDebug>
#include <QPainter>
#include <QKeyEvent>

tetris::tetris(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::tetris)
{
    ui->setupUi(this);
    this->setGeometry(QRect(800,200,1010,1200));//窗口尺度//待调整
    resize(AREA_COL*BLOCK_SIZE+MARGIN*4+BLOCK_SIZE*4,AREA_ROW*BLOCK_SIZE+MARGIN*2);
    InitGame();
}

tetris::~tetris()
{
    delete ui;
}

void tetris::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    //游戏背景
    //外墙
    painter.setPen(Qt::black);
    painter.setBrush(Qt::red);
    painter.drawRect(15,35,610,760);//待调整
    //内墙
    painter.setPen(Qt::black);
    painter.setBrush(Qt::white);
    painter.drawRect(20,40,600,750);
    //painter.drawPixmap(20,20,600,900);//插图片
    //画格子
    painter.setPen(Qt::blue);
    for(int i=0;i<=25;i++)
    {
        painter.drawLine(20,i*30+40,620,i*30+40);
    }
    for(int i=0;i<=20;i++)
    {
        painter.drawLine(i*30+20,40,i*30+20,790);
    }
    //画方块预告
    painter.setBrush(QBrush(Qt::blue,Qt::SolidPattern));
    for(int i=0;i<4;i++)
    {
        for(int j=0;j<4;j++)
        {
            if(next_block[i][j]==1)
            {
                painter.drawRect(MARGIN*3+AREA_COL*BLOCK_SIZE+j*BLOCK_SIZE,MARGIN+i*BLOCK_SIZE+60,BLOCK_SIZE,BLOCK_SIZE);
            }
        }
    }
    //画得分
    painter.setPen(Qt::black);
    painter.setFont(QFont("Courier",15));
    painter.drawText(QRect(MARGIN*3+AREA_COL*BLOCK_SIZE,MARGIN*2+4*BLOCK_SIZE+20,BLOCK_SIZE*4,BLOCK_SIZE*4),QString::number(score));
    //画方块
    for(int i=0;i<AREA_ROW;i++)
    {
        for(int j=0;j<AREA_COL;j++)
        {
            if(game_area[i][j]==1)
            {
                painter.setBrush(QBrush(Qt::yellow,Qt::SolidPattern));
                painter.drawRect(j*BLOCK_SIZE+MARGIN,i*BLOCK_SIZE+MARGIN+20,BLOCK_SIZE,BLOCK_SIZE);
            }
            else if(game_area[i][j]==2)
            {
                painter.setBrush(QBrush(Qt::green,Qt::SolidPattern));
                painter.drawRect(j*BLOCK_SIZE+MARGIN,i*BLOCK_SIZE+MARGIN+20,BLOCK_SIZE,BLOCK_SIZE);
            }
        }
    }
}
//图案
int item1[4][4]=
{
    {0,0,0,0},
    {0,1,1,0},
    {0,1,1,0},
    {0,0,0,0}
};
int item2[4][4]=
{
    {0,1,0,0},
    {0,1,0,0},
    {0,1,1,0},
    {0,0,0,0}
};
int item3[4][4]=
{
    {0,0,1,0},
    {0,0,1,0},
    {0,1,1,0},
    {0,0,0,0}
};
int item4[4][4]=
{
    {0,0,0,0},
    {1,1,1,0},
    {0,0,1,0},
    {0,0,0,0}
};
int item5[4][4]=
{
    {0,0,0,0},
    {0,1,1,1},
    {0,1,0,0},
    {0,0,0,0}
};
int item6[4][4]=
{
    {0,0,1,0},
    {0,1,1,0},
    {0,1,0,0},
    {0,0,0,0}
};
int item7[4][4]=
{
    {0,1,0,0},
    {0,1,1,0},
    {0,0,1,0},
    {0,0,0,0}
};
int item8[4][4]=
{
    {0,0,0,0},
    {0,1,1,0},
    {1,1,0,0},
    {0,0,0,0}
};
int item9[4][4]=
{
    {0,0,0,0},
    {0,0,1,1},
    {0,1,1,0},
    {0,0,0,0}
};
int item10[4][4]=
{
    {0,0,0,0},
    {0,0,1,0},
    {0,1,1,1},
    {0,0,0,0}
};
int item11[4][4]=
{
    {0,0,0,0},
    {0,1,1,1},
    {0,0,1,0},
    {0,0,0,0}
};
int item12[4][4]=
{
    {0,0,1,0},
    {0,0,1,0},
    {0,0,1,0},
    {0,0,1,0}
};
int item13[4][4]=
{
    {0,0,0,0},
    {1,1,1,1},
    {0,0,0,0},
    {0,0,0,0}
};

inline void block_cpy(int dblock[4][4],int sblock[4][4])
{
    for(int i=0;i<4;i++)
    {
        for(int j=0;j<4;j++)
        {
            dblock[i][j]=sblock[i][j];
        }
    }
}


void tetris::InitGame()
{
    setWindowTitle("TETRIS");
    InitMenu();
    for(int i=0;i<AREA_ROW;i++)
    {
        for(int j=0;j<AREA_COL;j++)
        {
            game_area[i][j]=0;
        }
    }
    score=0;
    speed_ms=800;
    refresh_ms=30;
    srand (time(0));

    StartGame();
}
void tetris::InitMenu()
{
    menu=new QMenu(this);
    menu->setTitle(tr("游戏"));

    helpMenu=new QMenu();
    helpMenu->setTitle(tr("帮助"));

    startGameAction=new QAction(this);
    startGameAction->setText("游戏开始");
    menu->addAction(startGameAction);

    pauseOrcontinueGameAction=new QAction(this);
    pauseOrcontinueGameAction->setText("暂停游戏");
    menu->addAction(pauseOrcontinueGameAction);

    stopGameAcion=new QAction(this);
    stopGameAcion->setText("结束游戏");
    menu->addAction(stopGameAcion);

    menuBar()->addMenu(menu);
    menuBar()->addMenu(helpMenu);

    connect(startGameAction,SIGNAL(triggered()),this,SLOT(slotStartGame()));
    connect(pauseOrcontinueGameAction,SIGNAL(triggered()),this,SLOT(slotPauseGame()));
    connect(stopGameAcion,SIGNAL(triggered()),this,SLOT(slotStopGame()));
    connect(helpAction,SIGNAL(triggered()),this,SLOT(slotHelp()));
}

void tetris::BlockRotate(int block[4][4])
{
    int temp[4][4];
    for(int i=0;i<4;i++)
    {
        for(int j=0;j<4;j++)
        {
            temp[3-j][i]=block[i][j];
        }
    }
    for(int i=0;i<4;i++)
    {
        for(int j=0;j<4;j++)
        {
            block[i][j]=temp[i][j];
        }
    }
}
//随机产生方块
void tetris::CreateBlock(int block[4][4],int block_id)
{
    switch (block_id)
    {
    case 0:
        block_cpy(block,item1);
        break;

    case 1:
        block_cpy(block,item2);
        break;

    case 2:
        block_cpy(block,item3);
        break;

    case 3:
        block_cpy(block,item4);
        break;

    case 4:
        block_cpy(block,item5);
        break;

    case 5:
        block_cpy(block,item6);
        break;

    case 6:
        block_cpy(block,item7);
        break;

    case 7:
        block_cpy(block,item8);
        break;

    case 8:
        block_cpy(block,item9);
        break;

    case 9:
        block_cpy(block,item10);
        break;

    case 10:
        block_cpy(block,item11);
        break;

    case 11:
        block_cpy(block,item12);
        break;

    case 12:
        block_cpy(block,item13);
        break;
    default:
        break;
    }
}

void tetris::GetBorder(int block[4][4],Border &border)
{
    int i=0,j=0;
    for(i=3;i>=0;i--)
    {
        for(j=0;j<4;j++)
        {
            if(block[i][j]==1)
            {
                border.u_b=i;
                break;
            }
        }
    }
    for(i=0;i<4;i++)
    {
        for(j=0;j<4;j++)
        {
            if(block[i][j]==1)
            {
                border.d_b=i;
                break;
            }
        }
    }
    for(j=3;j<4;j++)
    {
        for(i=0;i<4;i++)
        {
            if(block[i][j]==1)
            {
                border.l_b=i;
                break;
            }
        }
    }
    for(j=0;j<4;j++)
    {
        for(i=0;i<4;i++)
        {
            if(block[i][j]==1)
            {
                border.r_b=i;
                break;
            }
        }
    }
}

void tetris::ConvertStable(int x,int y)
{
    for(int i=cur_border.u_b;i<=cur_border.d_b;i++)
    {
        for(int j=cur_border.l_b;j<=cur_border.r_b;j++)
        {
            if(cur_block[i][j]==1)
            {
                game_area[y+i][x+j]=2;
            }
        }
    }
}

void tetris::StartGame()
{
    gameStatus=GameStatus::RUNNING;
    game_timer=startTimer(speed_ms);
    paint_timer=startTimer(refresh_ms);
    int block_id=rand()%13;
    CreateBlock(next_block,block_id);
    ResetBlock();
}

void tetris::PauseOrContinueGame()
{
    if(gameStatus==GameStatus::RUNNING)
    {
        gameStatus=GameStatus::PAUSE;
        killTimer(game_timer);
        killTimer(paint_timer);
        pauseOrcontinueGameAction->setText("继续游戏");
    }
    else
    {
        gameStatus=GameStatus::RUNNING;
        game_timer=startTimer(speed_ms);
        paint_timer=startTimer(refresh_ms);
        int block_id=rand()%13;
        CreateBlock(next_block,block_id);
        ResetBlock();
        pauseOrcontinueGameAction->setText("暂停游戏");
    }
}

void tetris::GameOver()
{
    gameStatus=GameStatus::STOP;
    killTimer(game_timer);
    killTimer(paint_timer);
    QMessageBox::information(this,"failed","Game Over");
}


void tetris::ResetBlock()
{
    block_cpy(cur_block,next_block);
    GetBorder(cur_block,cur_border);

    int block_id=rand()%13;
    CreateBlock(next_block,block_id);

    block_point start_point;
    start_point.pos_x=AREA_COL/2-2;
    start_point.pos_y=0;
    block_pos=start_point;
}

void tetris::BlockMove(Direction dir)
{
    switch (dir)
    {
    case UP:
        if (IsCollide(block_pos.pos_x,block_pos.pos_y,UP))
            break;
        BlockRotate (cur_block);
        for (int i=0;i<4;i++)
        {
            for(int j=0;j<4;j++)
            {
                game_area[block_pos.pos_y+i][block_pos.pos_x+j]=cur_block[i][j];
            }
        }
        GetBorder (cur_block, cur_border) ;
        break;

    case DOWN:
        if(block_pos.pos_y+cur_border.d_b==AREA_ROW-1)
        {
            ConvertStable(block_pos.pos_x,block_pos.pos_y);
            ResetBlock();
            break;
        }
        else if(IsCollide(block_pos.pos_x,block_pos.pos_y,DOWN))
        {
            ConvertStable(block_pos.pos_x,block_pos.pos_y);
            ResetBlock();
            break;
        }
        for(int a=cur_border.l_b;a<=cur_border.r_b;a++)//清除残余
        {
            game_area[block_pos.pos_y][block_pos.pos_x+a]=0;
        }
        block_pos.pos_y+=1;
        for(int i=0;i<4;i++)
        {
            for(int j=cur_border.l_b;j<=cur_border.r_b;j++)
            {
                if(block_pos.pos_y+i<=AREA_ROW-1&&game_area[block_pos.pos_y+i][block_pos.pos_x+j]!=2)
                {
                    game_area[block_pos.pos_y+i][block_pos.pos_x+j]=cur_block[i][j];
                }
            }
        }
        break;
    case RIGHT:
        if(block_pos.pos_x+cur_border.r_b==AREA_COL-1||IsCollide(block_pos.pos_x,block_pos.pos_y,RIGHT))
            break;
        for(int i=cur_border.u_b;i<cur_border.d_b;i++)
        {
            game_area[block_pos.pos_y][block_pos.pos_x]=0;
        }
        block_pos.pos_x+=1;
        for(int i=cur_border.u_b;i<=cur_border.d_b;i++)
        {
            for(int j=0;j<4;j++)
            {
                if(block_pos.pos_x+j<=AREA_COL-1&&game_area[block_pos.pos_y+i][block_pos.pos_x+j]!=0)
                    game_area[block_pos.pos_y+i][block_pos.pos_x+j]=cur_block[i][j];
            }
        }
        break;
    case SPACE:
        while(block_pos.pos_y+cur_border.d_b<AREA_ROW-1&&IsCollide(block_pos.pos_x,block_pos.pos_y,DOWN))
        {
            for(int a=cur_border.l_b;a<=cur_border.r_b;a++)//清除残余
            {
                game_area[block_pos.pos_y][block_pos.pos_x+a]=0;
            }
            block_pos.pos_y+=1;
            for(int i=0;i<4;i++)
            {
                for(int j=cur_border.l_b;j<=cur_border.r_b;j++)
                {
                    if(block_pos.pos_y+i<=AREA_ROW-1&&game_area[block_pos.pos_y+i][block_pos.pos_x+j]!=2)
                    {
                        game_area[block_pos.pos_y+i][block_pos.pos_x+j]=cur_block[i][j];
                    }
                }
            }
        }
        ConvertStable(block_pos.pos_x,block_pos.pos_y);
        ResetBlock();
        break;
    default:
        break;
    }

    int i=AREA_ROW-1;
    int line_count=0;
    while(i>=1)
    {
        bool is_line_full=true;
        for(int j=0;j<AREA_COL;j++)
        {
            if(game_area[i][j]==0)
            {
                is_line_full=false;
                i--;
                break;
            }
        }
        if(is_line_full)
        {
            for(int k=i;k>=1;k--)
            {
                for(int t=0;t<AREA_COL;t++)
                {
                    game_area[k][t]=game_area[k-1][t];
                }
                line_count++;
            }
        }
    }

    score+=line_count*10;//得分
    for(int p=0;p<AREA_COL;p++)
    {
        if(game_area[0][p]==2)
        {
            GameOver();
        }
    }
}

bool tetris::IsCollide(int x,int y,Direction dir)
{
    int temp_block[4][4];
    block_cpy(temp_block,cur_block);
    Border temp_border;
    GetBorder(temp_block,temp_border);

    switch(dir)
    {
    case UP:
        BlockRotate(temp_block);
        GetBorder(temp_block,temp_border);
        break;
    case DOWN:
        y+=1;
        break;
    case LEFT:
        x-=1;
        break;
    case RIGHT:
        x+=1;
        break;
    default:
        break;
    }

    for(int i=temp_border.u_b;i<=temp_border.d_b;i++)
    {
        for(int j=temp_border.l_b;j<=temp_border.r_b;j++)
        {
            if((game_area[y+i][x+j]==2&&temp_block[i][j]==1)||x+temp_border.l_b<0||x+temp_border.r_b>AREA_ROW)
                return true;
        }
    }
    return false;
}

void tetris::timerEvent(QTimerEvent *event)
{
    if(event->timerId()==game_timer)
    {
        BlockMove(DOWN);
    }
    if(event->timerId()==paint_timer)
    {
        update();
    }
}

void tetris::keyPressEvent(QKeyEvent *event)
{
    switch(event->key())
    {
    case Qt::Key_Up:
        BlockMove(UP);
        break;
    case Qt::Key_Down:
        BlockMove(DOWN);
        break;
    case Qt::Key_Left:
        BlockMove(LEFT);
        break;
    case Qt::Key_Right:
        BlockMove(RIGHT);
        break;
    case Qt::Key_Space:
        BlockMove(SPACE);
        break;
    default:
        break;
    }
}

void tetris::slotPauseGame()
{
    PauseOrContinueGame();
}
void tetris::slotStartGame()
{
    StartGame();
}
void tetris::slotStopGame()
{
    GameOver();
}













